import { v4 as uuidv4 } from 'uuid'
import { defineStore, acceptHMRUpdate } from 'pinia'
import { AllComponentProps, textDefaultProps } from '@isameng/lowcode-components'
import { ElMessage } from 'element-plus'
import { cloneDeep } from 'lodash-es'
import { insertAt } from '@/utils/utils'
import { request, WorkData, ListData } from '@/service/request'

export type MoveDirection = 'Up' | 'Down' | 'Left' | 'Right'

export type AllFormProps = PageProps & AllComponentProps

export interface PageProps {
  backgroundColor: string
  backgroundImage: string
  backgroundRepeat: string
  backgroundSize: string
  height: string
}

export interface PageData {
  id?: number
  props?: PageProps
  title?: string
  desc?: string
  coverImg?: string
  uuid?: string
  setting?: { [key: string]: any }
  isTemplate?: boolean // true 模版 false 非模版
  isPublic?: boolean // 是否公开到首页，默认 false
  isHot?: boolean
  author?: string
  copiedCount?: number // 被复制的次数
  status?: 0 | 1 | 2 | 3 // 状态：0-删除 1-未发布 2-发布 3-管理员强制下线
  user?: string
}

export interface ComponentData {
  // 元素属性
  props: Partial<AllComponentProps>
  // id， uuid v4 生成
  id: string
  // 业务组件库名称 h-text h-image ...
  name: string
  // 图层是否隐藏
  isHidden?: boolean
  // 图层是否锁定
  isLocked?: boolean
  // 图层名称
  layerName?: string
}

export interface HistoryProps {
  id: string
  componentId: string
  type: 'add' | 'delete' | 'modify'
  data: any
  index?: number
}

export interface UpdateComponentData {
  key: keyof AllComponentProps | Array<keyof AllComponentProps>
  value: string | string[]
  id: string
  isRoot?: boolean
}

export interface ChannelProps {
  id: string
  name: string
  workId: number
  status: number
}

export interface EditorProps {
  // 中间编辑器渲染的数组
  components: ComponentData[]
  // 当前编辑的是哪个元素，uuid
  currentElementId: string
  // 项目信息
  page: PageData
  // 当前被复制的组件
  copiedComponent?: ComponentData
  // 历史记录
  histories: HistoryProps[]
  // 记录历史记录操作位置
  historyIndex: number
  // 开始更新时的缓存值
  cachedOldValues: any
  // 保存最多历史条目记录数
  maxHistoryNumber: number
  // 数据是否有修改
  isDirty: boolean
  // 当前作品的渠道列表
  channels: ChannelProps[]
}

export const testComponents: ComponentData[] = [
  {
    id: uuidv4(),
    name: 'h-text',
    layerName: '图层1',
    props: {
      ...textDefaultProps,
      text: 'hello',
      fontSize: '20px',
      color: '#000000',
      lineHeight: '1',
      textAlign: 'left',
      fontFamily: '',
      width: '100px',
      height: '100px',
      backgroundColor: '#efefef',
      left: '100px',
      top: '150px'
    }
  }
  // {
  //   id: uuidv4(),
  //   name: 'h-image',
  //   layerName: '图层4',
  //   props: {
  //     ...imageDefaultProps,
  //     src: 'http://lowcode-backend.oss-cn-shenzhen.aliyuncs.com/lowcode-test/Nx-Dp3.png',
  //     width: '100px'
  //   }
  // }
]

const pageDefaultProps = {
  //url("http://lowcode-backend.oss-cn-shenzhen.aliyuncs.com/lowcode-test/eD-pfm.jpg")
  backgroundColor: '#ffffff',
  backgroundImage: '',
  backgroundRepeat: 'no-repeat',
  backgroundSize: 'cover',
  height: '560px' //560 622
}

function modifyHistory(history: HistoryProps, type: 'redo' | 'undo') {
  const store = useEditorStore()
  const { componentId, data } = history
  const { key, newValue, oldValue } = data
  const updatedComponent = store.components.find(component => component.id === componentId)
  if (updatedComponent) {
    if (Array.isArray(key)) {
      key.forEach((keyName, index) => {
        updatedComponent.props[keyName] = type === 'undo' ? oldValue[index] : newValue[index]
      })
    } else {
      updatedComponent.props[key] = type === 'undo' ? oldValue : newValue
    }
  }
}

function debounceChange(callback: (...args: any) => void, timeout = 1000) {
  let timer = null
  return function (...args: any) {
    // console.log(args)
    clearTimeout(timer)
    timer = setTimeout(() => {
      callback(...args)
    }, timeout)
  }
}

function pushHistory(historyRecord: HistoryProps) {
  const store = useEditorStore()
  // 检查 historyIndex 是否移动过
  if (store.historyIndex !== -1) {
    // 删掉大于等于 historyIndex 的历史记录
    store.histories = store.histories.slice(0, store.historyIndex)
    store.historyIndex = -1
  }

  // 检查历史操作记录长度
  if (store.histories.length < store.maxHistoryNumber) {
    store.histories.push(historyRecord)
  } else {
    store.histories.shift()
    store.histories.push(historyRecord)
  }
}

function pushModifyHistory({ key, value, id }: UpdateComponentData) {
  const store = useEditorStore()
  console.log(store.cachedOldValues)
  pushHistory({
    id: uuidv4(),
    componentId: id || store.currentElementId,
    type: 'modify',
    data: {
      oldValue: store.cachedOldValues,
      newValue: value,
      key
    }
  })
  store.cachedOldValues = null
}

const pushModifyHistoryDebounce = debounceChange(pushModifyHistory)

export const useEditorStore = defineStore('editor', {
  state: (): EditorProps => ({
    // components: testComponents,
    components: [],
    currentElementId: '',
    page: {
      props: pageDefaultProps
    },
    // page: {},
    histories: [],
    historyIndex: -1,
    cachedOldValues: null,
    maxHistoryNumber: 10,
    isDirty: false,
    channels: []
  }),

  getters: {
    getCurrentElement: state => {
      return state.components.find(component => component.id === state.currentElementId)
    },
    getComponentsLength: state => {
      return state.components.length
    },
    checkUndoDisable: state => {
      // 1、没有历史操作记录
      // 2、已经移动到第一个
      if (state.histories.length === 0 || state.historyIndex === 0) {
        return true
      }
      return false
    },
    checkRedoDisable: state => {
      // 1、没有历史操作记录
      // 2、已经移动到最后一个
      // 3、从来没有撤回过
      if (state.histories.length === 0 || state.historyIndex === state.histories.length || state.historyIndex === -1) {
        return true
      }
      return false
    }
  },

  actions: {
    addComponent(component: ComponentData) {
      this.isDirty = true
      component.layerName = '图层' + (this.components.length + 1)
      this.components.push(component)
      pushHistory({
        id: uuidv4(),
        componentId: component.id,
        type: 'add',
        data: cloneDeep(component)
      })
    },

    setActive(currentId: string) {
      this.currentElementId = currentId
    },

    // 撤销操作
    undo() {
      if (this.histories.length === 0 || this.historyIndex === 0) {
        return
      }
      // 没有 undo 记录
      if (this.historyIndex === -1) {
        // 从数组中拿到最后一项
        this.historyIndex = this.histories.length - 1
      } else {
        // 往前进一项
        this.historyIndex--
      }
      // 获取历史记录
      const history = this.histories[this.historyIndex]
      switch (history.type) {
        // 针对添加操作的撤销，就是要删除该元素
        case 'add':
          this.components = this.components.filter(component => component.id !== history.componentId)
          break
        // 针对删除操作的撤销，就是要添加该元素到对应的位置去
        case 'delete':
          this.components = insertAt(this.components, history.index, history.data)
          break
        // 找到对应的组件，修改回旧的值 oldValue
        case 'modify': {
          // const { componentId, data } = history
          // const { key, oldValue } = data
          // const updatedComponent = this.components.find(component => component.id === componentId)
          // if (updatedComponent) {
          //   updatedComponent.props[key] = oldValue
          // }
          modifyHistory(history, 'undo')
          break
        }
        default:
          break
      }
    },

    // 恢复操作
    redo() {
      if (this.histories.length === 0 || this.historyIndex === this.histories.length || this.historyIndex === -1) {
        return
      }
      const history = this.histories[this.historyIndex]
      switch (history.type) {
        case 'add':
          this.components.push(history.data)
          break
        case 'delete':
          this.components = this.components.filter(component => component.id !== history.componentId)
          break
        case 'modify': {
          // const { componentId, data } = history
          // const { key, newValue } = data
          // const updatedComponent = this.components.find(component => component.id === componentId)
          // if (updatedComponent) {
          //   updatedComponent.props[key] = newValue
          // }
          modifyHistory(history, 'redo')
          break
        }
        default:
          break
      }
      this.historyIndex++
    },

    // 复制图片
    copyComponent(id: string) {
      const currentComponent = this.components.find(component => component.id === id)
      if (currentComponent) {
        this.copiedComponent = currentComponent
        ElMessage.success('已拷贝当前图层')
      }
    },

    // 黏贴图层
    pasteCopiedComponent() {
      if (this.copiedComponent) {
        this.isDirty = true
        const clone = cloneDeep(this.copiedComponent)
        clone.id = uuidv4()
        clone.layerName = clone.layerName + '副本'
        this.components.push(clone)
        ElMessage.success('已黏贴当前图层')
        pushHistory({
          id: uuidv4(),
          componentId: clone.id,
          type: 'add',
          data: cloneDeep(clone)
        })
      }
    },

    // 删除图层
    deleteComponent(id: string) {
      const currentComponent = this.components.find(component => component.id === id)
      if (currentComponent) {
        this.isDirty = true
        const currentIndex = this.components.findIndex(component => component.id === id)
        this.components = this.components.filter(component => component.id !== id)
        pushHistory({
          id: uuidv4(),
          componentId: currentComponent.id,
          type: 'delete',
          data: currentComponent,
          index: currentIndex
        })
        ElMessage.success('删除当前图层成功')
      }
    },

    // 方向键移动图层
    moveComponent(data: { direction: MoveDirection; amount: number; id: string }) {
      const currentComponent = this.components.find(component => component.id === data.id)
      if (currentComponent) {
        const oldTop = parseInt(currentComponent.props.top || '0')
        const oldLeft = parseInt(currentComponent.props.left || '0')
        const { direction, amount } = data
        switch (direction) {
          case 'Up': {
            const newValue = oldTop - amount + 'px'
            this.updateComponent({ key: 'top', value: newValue, id: data.id })
            break
          }
          case 'Down': {
            const newValue = oldTop + amount + 'px'
            this.updateComponent({ key: 'top', value: newValue, id: data.id })
            break
          }
          case 'Left': {
            const newValue = oldLeft - amount + 'px'
            this.updateComponent({ key: 'left', value: newValue, id: data.id })
            break
          }
          case 'Right': {
            const newValue = oldLeft + amount + 'px'
            this.updateComponent({ key: 'left', value: newValue, id: data.id })
            break
          }
          default:
            break
        }
      }
    },

    // 修改组件样式属性
    updateComponent({ key, value, id, isRoot = false }: UpdateComponentData) {
      const updateComponent = this.components.find(component => component.id === (id || this.currentElementId))
      if (updateComponent) {
        this.isDirty = true
        // 更新根节点的属性
        if (isRoot) {
          updateComponent[key as string] = value
        } else {
          // 更新节点样式的属性
          // updateComponent.props[key as keyof AllComponentProps]
          const oldValue = Array.isArray(key) ? key.map(key => updateComponent.props[key]) : updateComponent.props[key]
          if (!this.cachedOldValues) {
            this.cachedOldValues = oldValue
          }
          pushModifyHistoryDebounce({ key, value, id })
          // this.histories.push({
          //   id: uuidv4(),
          //   componentId: id || this.currentElementId,
          //   type: 'modify',
          //   data: {
          //     oldValue,
          //     newValue: value,
          //     key
          //   }
          // })
          if (Array.isArray(key) && Array.isArray(value)) {
            key.forEach((keyName, index) => {
              updateComponent.props[keyName] = value[index]
            })
          } else if (typeof key === 'string' && typeof value === 'string') {
            updateComponent.props[key] = value
          }
        }
      }
    },

    // 修改页面样式属性
    updatePage({ key, value, isRoot = false, isSetting = false }) {
      this.isDirty = true
      if (isRoot) {
        this.page[key] = value
      } else if (isSetting) {
        this.page.setting = {
          ...this.page.setting,
          [key]: value
        }
      } else {
        if (this.page.props) {
          this.page.props[key] = value
        }
      }
    },

    // path-to-regexp  https://github.com/pillarjs/path-to-regexp
    async fetchWork(workId: string) {
      const { data } = await request<WorkData>(`/works/${workId}`, 'get', 'fetchWork')
      // 将后端的数据格式转化成界面渲染的格式
      const { content, ...rest } = data
      this.page = { ...this.page, ...rest }
      // this.page.props = pageDefaultProps
      if (content.props) {
        this.page.props = content.props
      }
      if (content.setting) {
        this.page.setting = content.setting
      }
      this.components = content.components
    },

    async saveWork(workId: string, payload: any) {
      const rawData = await request<WorkData>(`/works/${workId}`, 'patch', payload, 'saveWork')
      this.isDirty = false
      this.histories = []
      this.historyIndex = -1
      // 还可以展示修改的时间
      return rawData
    },

    async publishWork(workId: string) {
      await request(`works/publish/${workId}`, 'post')
    },

    async publishTemplate(workId: string) {
      await request(`works/publish-template/${workId}`, 'post')
    },

    async createWork(payload: any) {
      const rawData = await request<WorkData>('/works', 'post', payload)
      return rawData.data
    },

    async copyWork(workId: number) {
      const rawData = await request<WorkData>(`/works/copy/${workId}`, 'post')
      return rawData.data
    },

    async fetchChannels(workId: string) {
      const rawData = await request<ListData<ChannelProps>>(`/channels/getWorkChannels/${workId}`, 'get')
      this.channels = rawData.data.list
    },

    async createChannels(payload: any) {
      const rawData = await request<ChannelProps>('/channels', 'post', payload)
      // this.channels.push(rawData.data)
      this.channels = [...this.channels, rawData.data]
    },

    async deleteChannels(channelId: string) {
      await request(`channels/${channelId}`, 'delete')
      this.channels = this.channels.filter(channel => channel.id !== channelId)
    }
  }
})

if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(useEditorStore, import.meta.hot))
}
